package de.unikoblenz.west.csxpoi.server;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.BooleanQuery;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.http.HTTPRepository;

/**
 * REST interface for users.
 */
public class RestUsers extends HttpServlet {

	private static final long serialVersionUID = 1L;

	/**
	 * Handles GET requests.
	 */
	@Override
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (ServletHelper.isMemberRequest(request)) {

			try {

				String id = ServletHelper.resolveStringParameter(request, "id");
				String password = ServletHelper.resolveStringParameter(request,
						"password");

				UserWrapper user = null;

				Repository repository = new HTTPRepository(
						Constants.SESAME_SERVER, Constants.REPOSITORY_ID);

				try {
					repository.initialize();
					RepositoryConnection connection = repository
							.getConnection();

					try {

						user = UserWrapper.createFromUsername(id, password,
								connection);

					} finally {
						connection.close();
					}

					XmlWriter.writeUserResponse(response, user);

				} catch (RepositoryException e) {
					throw new ServerException();
				} catch (MalformedQueryException e) {
					throw new ServerException();
				} catch (QueryEvaluationException e) {
					throw new ServerException();
				}
			} catch (ServerException e) {
				XmlWriter.writeUserResponse(response, null);
			}

		} else { // ServletHelper.isCollectionRequest(request)
			// unused
		}
	}

	/**
	 * Handles POST requests.
	 */
	@Override
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (ServletHelper.isCollectionRequest(request)) {

			try {
				String username = ServletHelper.resolveStringParameter(request,
						"username");
				String password = ServletHelper.resolveStringParameter(request,
						"password");
				// TODO: foaf:name, foaf:mbox

				Repository repository = new HTTPRepository(
						Constants.SESAME_SERVER, Constants.REPOSITORY_ID);

				try {
					repository.initialize();
					RepositoryConnection connection = repository
							.getConnection();

					try {
						BooleanQuery testQuery = connection
								.prepareBooleanQuery(
										QueryLanguage.SPARQL,
										"PREFIX base: <"
												+ Constants.NS_BASE
												+ "> "
												+ "PREFIX foaf: <"
												+ Constants.NS_FOAF
												+ "> "
												+ "PREFIX xsd: <"
												+ Constants.NS_XSD
												+ "> "
												+ "ASK WHERE {"
												+ " ?user a base:User ;"
												+ "  foaf:nick ?username ."
												+ " FILTER (str(?username) = \""
												+ username + "\")" + "}");
						if (testQuery.evaluate())
							throw new ServerException();
					} finally {
						connection.close();
					}

					ValueFactory valueFactory = connection.getValueFactory();

					String userId = username.toLowerCase().replaceAll(" ", "");

					URI userUri = valueFactory.createURI(Constants.NS_USER
							+ userId);
					URI rdfTypeUri = valueFactory
							.createURI(Constants.URI_RDF_TYPE);
					URI baseUserUri = valueFactory
							.createURI(Constants.URI_BASE_USER);
					URI foafNickUri = valueFactory
							.createURI(Constants.URI_FOAF_NICK);
					URI basePasswordUri = valueFactory
							.createURI(Constants.URI_BASE_PASSWORD);
					URI xsdStringUri = valueFactory
							.createURI(Constants.URI_XSD_STRING);
					Literal usernameLiteral = valueFactory.createLiteral(
							username, xsdStringUri);
					Literal passwordLiteral = valueFactory.createLiteral(
							password, xsdStringUri);

					connection.add(userUri, rdfTypeUri, baseUserUri);
					connection.add(userUri, foafNickUri, usernameLiteral);
					connection.add(userUri, basePasswordUri, passwordLiteral);

					UserWrapper user = new UserWrapper();
					user.setUri(userUri.stringValue());
					user.setUsername(username);

					XmlWriter.writeUserResponse(response, user);

				} catch (RepositoryException e) {
					throw new ServerException();
				} catch (MalformedQueryException e) {
					throw new ServerException();
				} catch (QueryEvaluationException e) {
					throw new ServerException();
				}
			} catch (ServerException e) {
				XmlWriter.writeUserResponse(response, null);
			}
		} else { // ServletHelper.isMemberRequest(request)
			// unused
		}
	}

	/**
	 * Handles PUT requests.
	 */
	@Override
	protected void doPut(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (ServletHelper.isMemberRequest(request)) {

			try {

				String id = ServletHelper.resolveStringParameter(request, "id");
				String password = ServletHelper.resolveStringParameter(request,
						"password");

				UserWrapper user = null;

				Repository repository = new HTTPRepository(
						Constants.SESAME_SERVER, Constants.REPOSITORY_ID);

				try {
					repository.initialize();
					RepositoryConnection connection = repository
							.getConnection();

					try {

						user = UserWrapper.createFromUsername(id, password,
								connection);
						if (user == null)
							throw new ServerException();

						ValueFactory valueFactory = connection
								.getValueFactory();

						URI userUri = valueFactory.createURI(user.getUri());
						URI nameUri = valueFactory
								.createURI(Constants.URI_FOAF_NAME);
						URI emailUri = valueFactory
								.createURI(Constants.URI_FOAF_MBOX);
						URI passwordUri = valueFactory
								.createURI(Constants.URI_BASE_PASSWORD);
						URI stringUri = valueFactory
								.createURI(Constants.URI_XSD_STRING);

						if (request.getParameter("newName") != null) {
							Literal nameLiteral = valueFactory.createLiteral(
									ServletHelper.resolveStringParameter(
											request, "newName"), stringUri);
							connection.remove(userUri, nameUri, null);
							connection.add(userUri, nameUri, nameLiteral);
						}
						if (request.getParameter("newEmail") != null) {
							Literal emailLiteral = valueFactory.createLiteral(
									ServletHelper.resolveStringParameter(
											request, "newEmail"), stringUri);
							connection.remove(userUri, emailUri, null);
							connection.add(userUri, emailUri, emailLiteral);
						}
						if (request.getParameter("newPassword") != null) {
							Literal passwordLiteral = valueFactory
									.createLiteral(ServletHelper
											.resolveStringParameter(request,
													"newPassword"), stringUri);
							connection.remove(userUri, passwordUri, null);
							connection.add(userUri, passwordUri,
									passwordLiteral);
						}
					} finally {
						connection.close();
					}

					XmlWriter.writeUserResponse(response, user);

				} catch (RepositoryException e) {
					throw new ServerException();
				} catch (MalformedQueryException e) {
					throw new ServerException();
				} catch (QueryEvaluationException e) {
					throw new ServerException();
				}
			} catch (ServerException e) {
				XmlWriter.writeUserResponse(response, null);
			}

		} else { // ServletHelper.isCollectionRequest(request)
			// unused
		}
	}

	/**
	 * Handles DELETE requests.
	 */
	@Override
	protected void doDelete(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (ServletHelper.isMemberRequest(request)) {

			try {

				String id = ServletHelper.resolveStringParameter(request, "id");
				String password = ServletHelper.resolveStringParameter(request,
						"password");

				UserWrapper user = null;

				Repository repository = new HTTPRepository(
						Constants.SESAME_SERVER, Constants.REPOSITORY_ID);

				try {
					repository.initialize();
					RepositoryConnection connection = repository
							.getConnection();

					try {

						user = UserWrapper.createFromUsername(id, password,
								connection);
						if (user == null)
							throw new ServerException();

						ValueFactory valueFactory = connection
								.getValueFactory();

						URI userUri = valueFactory.createURI(user.getUri());

						connection.remove(userUri, null, null);

					} finally {
						connection.close();
					}

					XmlWriter.writeUserResponse(response, user);

				} catch (RepositoryException e) {
					throw new ServerException();
				} catch (MalformedQueryException e) {
					throw new ServerException();
				} catch (QueryEvaluationException e) {
					throw new ServerException();
				}
			} catch (ServerException e) {
				XmlWriter.writeUserResponse(response, null);
			}

		} else { // ServletHelper.isCollectionRequest(request)
			// unused
		}
	}

}
